//////////////////////////////////////////////////////////////////////
//
//  arrayslice_cimp.cpp
//
//  The core implementation of slicing of logical/numeric arrays
//
//  Created by Dahua Lin, on Dec 21, 2007
//
//////////////////////////////////////////////////////////////////////

#include "mex.h"

#include <memory.h>

inline int getnumel(mwSize dim, const mwSize *siz)
{
	mwSize s = 1;
	for (int i = 0; i < dim; ++i)
	{
		s *= siz[i];
	}
	return s;
}

inline mwSize* getsize(const mxArray *mxSiz, mwSize& dim)
{
    dim = mxGetNumberOfElements(mxSiz);
    mwSize *sizs = new mwSize[dim];
    
    const int *data = reinterpret_cast<const int*>(mxGetData(mxSiz));
    for (int i = 0; i < dim; ++i)
    {        
        sizs[i] = (mwSize)data[i];
    }
    
    return sizs;
}



mxArray* make_slices(const mxArray *mxSrc, const mxClassID classid,
					 int dim_cells, const mwSize *siz_cells,
					 mwSize dim_blk, const mwSize *siz_blk, int ebytes)
{
	mxArray *mxCell = mxCreateCellArray(dim_cells, siz_cells);

	int bn = getnumel(dim_blk, siz_blk);
	int nc = getnumel(dim_cells, siz_cells);

	const char *src = reinterpret_cast<const char*>(mxGetData(mxSrc));
	int blkbytes = ebytes * bn;

	for (mwIndex i = 0; i < nc; ++i)
	{
		mxArray *mxBlock = mxCreateNumericArray(
			dim_blk, siz_blk, classid, mxREAL);

		memcpy(mxGetData(mxBlock), src, blkbytes);
		src += blkbytes;
			
		mxSetCell(mxCell, i, mxBlock);
	}

	return mxCell;	
}


/*
 * main entry
 *
 * Input
 *   - A:           the source array (logical or numeic types)
 *   - sizcells:    the row vector of the size of cell array (int32)
 *   - sizslice:    the row vector of the size of slice (int32)
 * Output
 *   - the cell array of slices
 *
 * For efficiency, no checking inside the mex function
 */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	const mxArray *mxA = prhs[0];
	const mxArray *mxSizCells = prhs[1];
	const mxArray *mxSizSlice = prhs[2];

	mxClassID classid = mxGetClassID(mxA);
	size_t ebytes = mxGetElementSize(mxA);

    mwSize dim_cells = 0;
	mwSize *siz_cells = getsize(mxSizCells, dim_cells);
    
    mwSize dim_slice = 0;
    mwSize *siz_slice = getsize(mxSizSlice, dim_slice);

	mxArray *mxCell = make_slices(mxA, classid, dim_cells, siz_cells,
								  dim_slice, siz_slice, ebytes);
    
    delete[] siz_cells;
    delete[] siz_slice;
    
	plhs[0] = mxCell;
    
}


